/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "utgarde_keep.h"

enum eDisplayId
{
	DISPLAYID_DEFAULT				= 21953,
	DISPLAYID_UNDEAD				= 26351,
};

enum eNPCs
{
	NPC_INGVAR_UNDEAD				= 23980,
	NPC_ANNHYLDE					= 24068,
	NPC_THROW						= 23997,
};

enum Yells
{
    //Yells Ingvar
    YELL_AGGRO_1                                = 0,
    YELL_KILL_1                                 = 1,
    YELL_DEAD_1                                 = 2,

    YELL_AGGRO_2                                = 3,
    YELL_KILL_2                                 = 4,
    YELL_DEAD_2                                 = 5,

    EMOTE_ROAR                                  = 6,
    YELL_ANHYLDE_1                              = 0,
    YELL_ANHYLDE_2                              = 1,
};

enum eSpells
{
	SPELL_SUMMON_VALKYR				= 42912,
	SPELL_RESURRECTION_BEAM			= 42857,
	SPELL_RESURRECTION_BALL			= 42862,
	SPELL_RESURRECTION_HEAL			= 42704,
	SPELL_INGVAR_TRANSFORM			= 42796,

	SPELL_STAGGERING_ROAR_N			= 42708,
    SPELL_STAGGERING_ROAR_H			= 59708,
	SPELL_CLEAVE					= 42724,
    SPELL_SMASH_N					= 42669,
    SPELL_SMASH_H					= 59706,
	SPELL_ENRAGE_N					= 42705,
    SPELL_ENRAGE_H					= 59707,

    SPELL_DREADFUL_ROAR_N			= 42729,
    SPELL_DREADFUL_ROAR_H			= 59734,
    SPELL_WOE_STRIKE_N				= 42730,
    SPELL_WOE_STRIKE_H				= 59735,
	SPELL_DARK_SMASH				= 42723,
	SPELL_SHADOW_AXE				= 42749,
};

#define SPELL_STAGGERING_ROAR		DUNGEON_MODE(SPELL_STAGGERING_ROAR_N, SPELL_STAGGERING_ROAR_H)
#define SPELL_DREADFUL_ROAR			DUNGEON_MODE(SPELL_DREADFUL_ROAR_N, SPELL_DREADFUL_ROAR_H)
#define SPELL_WOE_STRIKE			DUNGEON_MODE(SPELL_WOE_STRIKE_N, SPELL_WOE_STRIKE_H)
#define SPELL_SMASH					DUNGEON_MODE(SPELL_SMASH_N, SPELL_SMASH_H)
#define SPELL_ENRAGE				DUNGEON_MODE(SPELL_ENRAGE_N, SPELL_ENRAGE_H)

enum eEvents
{
	EVENT_START_RESURRECTION = 1,
	EVENT_YELL_DEAD_1,
	EVENT_VALKYR_MOVE,
	EVENT_ANNHYLDE_YELL,
	EVENT_VALKYR_BEAM,
	EVENT_RESURRECTION_BALL,
	EVENT_RESURRECTION_HEAL,
	EVENT_MORPH_TO_UNDEAD,
	EVENT_START_PHASE_2,

	EVENT_UNROOT,
	EVENT_SPELL_ROAR,
	EVENT_SPELL_CLEAVE_OR_WOE_STRIKE,
	EVENT_SPELL_SMASH,
	EVENT_SPELL_ENRAGE_OR_SHADOW_AXE,
	EVENT_AXE_RETURN,
	EVENT_AXE_PICKUP,
};

class boss_ingvar_the_plunderer : public CreatureScript
{
public:
	boss_ingvar_the_plunderer() : CreatureScript("boss_ingvar_the_plunderer") { }

	CreatureAI* GetAI(Creature* pCreature) const
	{
		return new boss_ingvar_the_plundererAI(pCreature);
	}

	struct boss_ingvar_the_plundererAI : public ScriptedAI
	{
		boss_ingvar_the_plundererAI(Creature *c) : ScriptedAI(c), summons(me)
		{
			pInstance = c->GetInstanceScript();
		}

		InstanceScript* pInstance;
		EventMap events;
		SummonList summons;
		uint64 ValkyrGUID;
		uint64 ThrowGUID;

		void Reset()
		{
			ValkyrGUID = 0;
			ThrowGUID = 0;
			events.Reset();
			summons.DespawnAll();
			me->SetDisplayId(DISPLAYID_DEFAULT);
			me->LoadEquipment(1);
			FeignDeath(false);
			me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
			me->SetControlled(false, UNIT_STATE_ROOT);
			me->DisableRotate(false);

			if (pInstance)
				pInstance->SetData(DATA_INGVAR, NOT_STARTED);
		}

		void DamageTaken(Unit*, uint32 &damage, DamageEffectType, SpellSchoolMask)
		{
			if (me->GetDisplayId() == DISPLAYID_DEFAULT && damage >= me->GetHealth())
			{
				damage = 0;
				me->InterruptNonMeleeSpells(true);
				me->RemoveAllAuras();
				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
				me->SetControlled(false, UNIT_STATE_ROOT);
				me->DisableRotate(false);
				me->GetMotionMaster()->MovementExpired();
				me->GetMotionMaster()->MoveIdle();
				me->StopMoving();
				FeignDeath(true);
				events.Reset();
				events.RescheduleEvent(EVENT_START_RESURRECTION, 1000);
				events.RescheduleEvent(EVENT_YELL_DEAD_1, 0);
			}
		}

		void EnterCombat(Unit * /*who*/)
		{
			events.Reset();
			// schedule Phase 1 abilities
			events.RescheduleEvent(EVENT_SPELL_ROAR, 15000);
			events.RescheduleEvent(EVENT_SPELL_CLEAVE_OR_WOE_STRIKE, 2000);
			events.RescheduleEvent(EVENT_SPELL_SMASH, 5000);
			events.RescheduleEvent(EVENT_SPELL_ENRAGE_OR_SHADOW_AXE, 10000);

			Talk(YELL_AGGRO_1);
			me->LowerPlayerDamageReq(me->GetMaxHealth());

			if (pInstance)
				pInstance->SetData(DATA_INGVAR, IN_PROGRESS);
		}

		void JustSummoned(Creature* s)
		{
			summons.Summon(s);
			if (s->GetEntry() == NPC_ANNHYLDE)
			{
				ValkyrGUID = s->GetGUID();
				s->SetCanFly(true);
				s->SetDisableGravity(true);
				s->SetHover(true);
				s->SetPosition(s->GetPositionX(), s->GetPositionY(), s->GetPositionZ()+35.0f, s->GetOrientation());
				s->SetFacingTo(s->GetOrientation());
			}
			else if (s->GetEntry() == NPC_THROW)
			{
				ThrowGUID = s->GetGUID();
				if( Unit* t = SelectTarget(SELECT_TARGET_RANDOM, 0, 70.0f, true) )
					s->GetMotionMaster()->MovePoint(0, t->GetPositionX(), t->GetPositionY(), t->GetPositionZ());
			}
		}

		void KilledUnit(Unit* /*who*/)
		{
			if (me->GetDisplayId() == DISPLAYID_DEFAULT)
				Talk(YELL_KILL_2);
			else
				Talk(YELL_KILL_1);
		}

		void FeignDeath(bool apply)
		{
			if (apply)
			{
				me->SetStandState(UNIT_STAND_STATE_DEAD);
				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
				me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
				me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
			}
			else
			{
				me->SetStandState(UNIT_STAND_STATE_STAND);
				me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
				me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
				me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
			}
		}

		void JustDied(Unit* /*killer*/)
		{
			events.Reset();
			summons.DespawnAll();
			Talk(YELL_DEAD_2);
			if (pInstance)
			{
				pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_INGVAR_UNDEAD, 1); // undead entry needed for achievements
				pInstance->SetData(DATA_INGVAR, DONE);
			}
		}

		void EnterEvadeMode()
		{
			me->SetControlled(false, UNIT_STATE_ROOT);
			me->DisableRotate(false);
			ScriptedAI::EnterEvadeMode();
		}

		void UpdateAI(uint32 diff)
		{
			if (!UpdateVictim())
				return;

			events.Update(diff);

			if( me->HasUnitState(UNIT_STATE_CASTING) )
				return;

			switch( events.GetEvent() )
			{
				case 0:
					break;
				case EVENT_YELL_DEAD_1:
					Talk(YELL_DEAD_1);
					events.PopEvent();
					break;
				case EVENT_START_RESURRECTION:
					me->CastSpell(me, SPELL_SUMMON_VALKYR, true);
					events.PopEvent();
					events.RescheduleEvent(EVENT_VALKYR_BEAM, 7000);
					events.RescheduleEvent(EVENT_VALKYR_MOVE, 1);
					events.RescheduleEvent(EVENT_ANNHYLDE_YELL, 3000);
					break;
				case EVENT_VALKYR_MOVE:
					if( Creature* s = ObjectAccessor::GetCreature(*me, ValkyrGUID) )
						s->GetMotionMaster()->MovePoint(1, s->GetPositionX(), s->GetPositionY(), s->GetPositionZ()-15.0f);
					events.PopEvent();
					break;
				case EVENT_ANNHYLDE_YELL:
					if( Creature* s = ObjectAccessor::GetCreature(*me, ValkyrGUID) )
						s->AI()->Talk(YELL_ANHYLDE_2);
					events.PopEvent();
					break;
				case EVENT_VALKYR_BEAM:
					me->RemoveAura(SPELL_SUMMON_VALKYR);
					if( Creature* c = ObjectAccessor::GetCreature(*me, ValkyrGUID) )
						c->CastSpell(me, SPELL_RESURRECTION_BEAM, false);
					events.PopEvent();
					events.RescheduleEvent(EVENT_RESURRECTION_BALL, 4000);
					break;
				case EVENT_RESURRECTION_BALL:
					me->CastSpell(me, SPELL_RESURRECTION_BALL, true);
					events.PopEvent();
					events.RescheduleEvent(EVENT_RESURRECTION_HEAL, 4000);
					break;
				case EVENT_RESURRECTION_HEAL:
					me->RemoveAura(SPELL_RESURRECTION_BALL);
					me->CastSpell(me, SPELL_RESURRECTION_HEAL, true);
					FeignDeath(false);
					events.PopEvent();
					events.RescheduleEvent(EVENT_MORPH_TO_UNDEAD, 3000);
					break;
				case EVENT_MORPH_TO_UNDEAD:
					me->CastSpell(me, SPELL_INGVAR_TRANSFORM, true);
					events.PopEvent();
					events.RescheduleEvent(EVENT_START_PHASE_2, 1000);
					break;
				case EVENT_START_PHASE_2:
					if( Creature* c = ObjectAccessor::GetCreature(*me, ValkyrGUID) )
					{
						c->DespawnOrUnsummon();
						summons.DespawnAll();
					}
					events.PopEvent();
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
					AttackStart(me->GetVictim());
					me->GetMotionMaster()->MoveChase(me->GetVictim());
					Talk(YELL_AGGRO_2);

					// schedule Phase 2 abilities
					events.RescheduleEvent(EVENT_SPELL_ROAR, 15000);
					events.RescheduleEvent(EVENT_SPELL_CLEAVE_OR_WOE_STRIKE, 2000);
					events.RescheduleEvent(EVENT_SPELL_SMASH, 5000);
					events.RescheduleEvent(EVENT_SPELL_ENRAGE_OR_SHADOW_AXE, 10000);

					break;

				// ABILITIES HERE:
				case EVENT_UNROOT:
					me->SetControlled(false, UNIT_STATE_ROOT);
					me->DisableRotate(false);
					events.PopEvent();
					break;
				case EVENT_SPELL_ROAR:
					Talk(EMOTE_ROAR);

					me->_AddCreatureSpellCooldown(SPELL_STAGGERING_ROAR, 0);
					me->_AddCreatureSpellCooldown(SPELL_DREADFUL_ROAR, 0);

					if (me->GetDisplayId() == DISPLAYID_DEFAULT)
						me->CastSpell((Unit*)NULL, SPELL_STAGGERING_ROAR, false);
					else
						me->CastSpell((Unit*)NULL, SPELL_DREADFUL_ROAR, false);
					events.RepeatEvent(urand(15000,20000));
					break;
				case EVENT_SPELL_CLEAVE_OR_WOE_STRIKE:
					if( me->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID) == 0 )
					{
						events.RepeatEvent(3000);
						break;
					}
					if (me->GetDisplayId() == DISPLAYID_DEFAULT)
						me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
					else
						me->CastSpell(me->GetVictim(), SPELL_WOE_STRIKE, false);
					events.RepeatEvent(urand(0,4000)+3000);
					break;
				case EVENT_SPELL_SMASH:
					if( me->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID) == 0 )
					{
						events.RepeatEvent(3000);
						break;
					}
					me->SetControlled(true, UNIT_STATE_ROOT);
					me->DisableRotate(true);
					me->SendMovementFlagUpdate();
					if (me->GetDisplayId() == DISPLAYID_DEFAULT)
						me->CastSpell((Unit*)NULL, SPELL_SMASH, false);
					else
						me->CastSpell((Unit*)NULL, SPELL_DARK_SMASH, false);
					events.RepeatEvent(urand(9000,11000));
					events.RescheduleEvent(EVENT_UNROOT, 3750);
					break;
				case EVENT_SPELL_ENRAGE_OR_SHADOW_AXE:
					if (me->GetDisplayId() == DISPLAYID_DEFAULT)
					{
						me->CastSpell(me, SPELL_ENRAGE, false);
						events.RepeatEvent(10000);
					}
					else
					{
						me->CastSpell((Unit*)NULL, SPELL_SHADOW_AXE, true);
						SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
						events.RepeatEvent(35000);
						events.RescheduleEvent(EVENT_AXE_RETURN, 10000);
					}
					break;
				case EVENT_AXE_RETURN:
					if (Creature* c = ObjectAccessor::GetCreature(*me, ThrowGUID))
						c->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+0.5f);
					events.PopEvent();
					events.RescheduleEvent(EVENT_AXE_PICKUP, 1500);
					break;
				case EVENT_AXE_PICKUP:
					if (Creature* c = ObjectAccessor::GetCreature(*me, ThrowGUID))
					{
						c->DestroyForNearbyPlayers();
						c->DespawnOrUnsummon();
						summons.DespawnAll();
					}
					ThrowGUID = 0;
					SetEquipmentSlots(true);
					events.PopEvent();
					break;
			}

			if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
				DoMeleeAttackIfReady();
		}
	};
};

void AddSC_boss_ingvar_the_plunderer()
{
	new boss_ingvar_the_plunderer();
}
